package uebung02;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;

import tools.Arrow;

public class PickingTheRightPixels {
	static int count = 2000;

	public static void main(String[] args) throws Exception {
		try {
			final BufferedImage kermit = ImageIO.read(Thread.currentThread().getContextClassLoader().getResourceAsStream("res/kermit001.jpg"));
			final int w = kermit.getWidth(), h = kermit.getHeight(), w2 = w / 2, h2 = h / 2;
			// int n = 16;

			final int[] pixels = kermit.getRGB(0, 0, w, h, new int[w * h], 0, w);

			final MemoryImageSource mis = new MemoryImageSource(w, h, pixels,0, w);
			mis.setAnimated(true);
			
			double theta = Math.toRadians(13);

			final AffineTransform at2 = AffineTransform.getTranslateInstance(
					0.25, 0.125);
			at2.preConcatenate(AffineTransform.getScaleInstance(2, 2));
			final AffineTransform at = new AffineTransform();
			at2.concatenate(AffineTransform.getRotateInstance(theta));

			final Rectangle2D selection = new Rectangle2D.Double();

			Point2D centerD = new Point2D.Double();
			centerD = at2.transform(centerD, centerD);
			final AffineTransform invers = at2.createInverse();

			JFrame ff = new JFrame();
			ff.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
			Point2D a = new Point2D.Double(100, 100), b = new Point2D.Double(
					500, 300);

			mis.newPixels();
			kermit.setRGB(0, 0, w, h, pixels, 0, w);
			double arrowWidth = 10, arrowHeight = 40;

			final Arrow arrw = new Arrow();
			arrw.setArrow(a, b, arrowWidth, arrowHeight);
			final AffineTransform translator = AffineTransform.getTranslateInstance(w / 2, h / 2);

			final ArrayList<Integer> pix = new ArrayList<Integer>(), sel = new ArrayList<Integer>();
			
			final JComponent canvas = new JComponent() {
				{
					setPreferredSize(new Dimension(w, h));
				}
				Line2D line = new Line2D.Double();
				Image im = createImage(mis);

				@Override
				public void paint(Graphics g) {
					Graphics2D g2 = (Graphics2D) g;

					g2.transform(at);

					g2.drawImage(im, 0, 0, this);

					g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
							RenderingHints.VALUE_ANTIALIAS_ON);
					g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,
							RenderingHints.VALUE_STROKE_PURE);
					g2.setRenderingHint(RenderingHints.KEY_RENDERING,
							RenderingHints.VALUE_RENDER_QUALITY);
					g2.setStroke(new BasicStroke(0.3f));

					g2.setColor(Color.cyan);
					line.setLine(0, h / 2, w, h / 2);
					g2.draw(line);
					line.setLine(w / 2, 0, w / 2, h);
					g2.draw(line);

					g2.setColor(Color.magenta);
					for (int x = -2; x < 2; x++) {
						for (int y = -2; y < 2; y++) {
							selection.setFrame(x * 4, y * 4, 4, 4);
							Shape transSelection = at2
									.createTransformedShape(selection);
							Rectangle bounds = translator.createTransformedShape(transSelection).getBounds();

							g2.setColor(Color.magenta);
							g2.draw(bounds);
							Point2D p = new Point2D.Double();
//							Shape inversTransBounds = invers.createTransformedShape(bounds);
//							bounds = inversTransBounds.getBounds();
							g2.setColor(Color.magenta);
							g2.draw(selection);
							g2.setColor(Color.yellow);
							g2.draw(translator.createTransformedShape(at2.createTransformedShape(selection)));
						}
					}
					super.paint(g);
				}
			};
			for (int x = -2; x < 2; x++) {
				for (int y = -2; y < 2; y++) {
					selection.setFrame(x * 4, y * 4, 4, 4);
					Shape transSelection = translator.createTransformedShape(at2.createTransformedShape(selection));
					Rectangle bounds = transSelection.getBounds();

					Point2D p = new Point2D.Double();
					for (int j = (int) Math.floor(bounds.getMinY()), endy = (int) Math.ceil(bounds.getMaxY()); j < endy; j++) {
						for (int i = (int) Math.floor(bounds.getMinX()), endx = (int) Math.ceil(bounds.getMaxX()); i < endx; i++) {
							pix.add(i);
							pix.add(j);
							p.setLocation(i, j);
							
							if (transSelection.contains(p)) {
	
								sel.add(i);
								sel.add(j);
							}
						}
					}
				}
			}

			
			for (int i = 0; i<pix.size(); i+=2) {
				pixels[pix.get(i)+pix.get(i+1)*w] = 0xFF0000FF;
			}
			for (int i = 0; i<sel.size(); i+=2) {
				pixels[sel.get(i)+sel.get(i+1)*w] = 0xFF00ff00;
			}
			mis.newPixels();
			canvas.repaint();
			canvas.addMouseWheelListener(new MouseWheelListener() {

				@Override
				public void mouseWheelMoved(MouseWheelEvent e) {

					double scale = Math.pow(1.01, e.getWheelRotation());

					try {
						Point2D p = new Point2D.Double(e.getX(), e.getY());
						at.inverseTransform(p, p);
						at.concatenate(AffineTransform.getTranslateInstance(p.getX(), p.getY()));
						at.concatenate(AffineTransform.getScaleInstance(scale,scale));
						at.concatenate(AffineTransform.getTranslateInstance(-p.getX(), -p.getY()));

					} catch (NoninvertibleTransformException nte) {
						nte.printStackTrace();
					}
					canvas.repaint();
				}
			});
			ff.add(canvas);
			ff.pack();

			ff.setVisible(true);
		} catch (IOException iox) {
			iox.printStackTrace();
		}
	}
}
